安安,我是 ChiYu!
昨天,我們再次實踐了「文件驅動開發」的核心精神。我們沒有直接衝進複雜的圖表程式碼中,而是先退一步,將一個模糊的「想法」,轉化為了一份清晰、具體、可執行的「技術規格」。
我們手上現在握著一份像素級精密的「零件設計圖」。有了它,我們接下來的開發工作將會變得無比順暢,因為所有關於「如何設計」的燒腦問題,都已經被解決了。我們的任務只剩下一個——專注於「如何實現」。
今天,我們將正式拿起工具,嚴格依據昨天的這份《圖表元件規格書》,指揮 AI 和 Chart.js,將這幅數據的畫布,變成真實、可互動的前端程式碼!
在開始之前,讓我們再次鞏固一下心法。為什麼像我們昨天產出的那份規格書,在專業團隊中如此重要?
Props
定義來接收數據,嚴格按照這份文件的『互動行為』來寫 JS 邏輯。」這能確保 AI 的強大創造力,永遠在我們設定好的軌道上馳騁。好了,理論不再贅述,讓我們進入 gemini chat 模式,開始我們今天精彩的 Vibe Coding 之旅!
首先,我們要為專案引入一個強大且易用的圖表函式庫。
# 角色
你是一位熟悉前端生態系的前端工程師。
**# 任務**
請修改 `@frontend/index.html`,為專案引入 Chart.js 函式庫。
**# 產出要求**
請在 `<head>` 區塊中,加入 Chart.js 的 CDN 連結。請使用最新穩定版本。
AI 會為我們找到 Chart.js 的 CDN,並將 <script>
標籤加入到我們的 HTML 中。
我們需要在 HTML 中,為圖表預留一個位置。
# 角色 (Role)
你是一位資深前端工程師,精通語意化 HTML、**無障礙網頁設計 (Accessibility)**,並擅長為複雜的 JavaScript 元件搭建穩固的 DOM 結構。
# 目標 (Objective)
請為我們的「關聯性洞察圖表」元件,在主 HTML 檔案中,**搭建其渲染的掛載點 (rendering mount point)**。這個結構必須同時考慮到 Chart.js 的渲染需求與無障礙設計的最佳實踐。
# 上下文與關鍵資訊 (Context & Key Information)
* **目標修改檔案**: `@frontend/index.html`
* **元件規格書**: `@docs/CHART_COMPONENT_SPEC.md` (此操作應遵循規格書的規劃)。
* **欲掛載元件**: Chart.js 驅動的圖表。
* **預期位置**: 在 `<main class="main-content">` 區域中,建議放置於「心情追蹤器」 (`mood-tracker-container`) 之後。
# 產出格式與要求 (Your Task & Output Requirements)
1. **直接修改**: 請直接重寫 `@frontend/index.html` 的內容,將新區塊加入。
2. **語意化結構**:
* 建立一個語義化的 `<section>` 元素作為圖表容器,並賦予其 `class="chart-container"`。
* 在容器內部,可以放置一個 `<h2>` 標題,例如「關聯性洞察」。
3. **Canvas 元素**:
* 在 `<section>` 內部,放置一個 `<canvas>` 元素,並賦予其 `id="insightChart"`。
4. **無障礙設計 (Accessibility) - (關鍵要求)**:
* 為 `<canvas>` 元素加上 `role="img"` 屬性,向輔助技術表明這是一個圖像。
* 為 `<canvas>` 元素加上一個描述性的 `aria-label`,例如 `aria-label="心情趨勢與習慣完成關聯圖表"`。
* 在 `<canvas>` 標籤的**內部**,提供一段**備用文字 (Fallback Content)**,例如 `<p>您的瀏覽器不支援圖表顯示,此處為心情與習慣的關聯性數據圖表。</p>`。這對不支援 canvas 的瀏覽器或某些螢幕閱讀器至關重要。
5. **HTML 註解**: 請使用清晰的 HTML 註解,標示出圖表容器區塊的開始與結束,以提高程式碼的可維護性。
這是今天的重頭戲!我們將把昨天嘔心瀝血寫的規格書,當作一份完整的「施工命令單」,交給 AI 來執行。
# 角色 (Role)
你是一位頂尖的 JavaScript 開發者與數據視覺化架構師,是 Chart.js 的資深專家。你不僅擅長將複雜的規格轉化為美觀的圖表,更注重程式碼的**效能、可維護性與架構的優雅性**。
# 目標 (Objective)
請**嚴格依據**《圖表元件技術規格書》,在 `@frontend/script.js` 中,實現一個**高效能、可複用、且與現有狀態管理機制深度整合的**「關聯性洞察圖表」渲染模組。
# 上下文與關鍵資訊 (Context & Key Information)
* **唯一真理來源**: `@docs/CHART_COMPONENT_SPEC.md` (所有視覺、互動、數據格式的最終裁決依據)。
* **目標修改檔案**: `@frontend/script.js`。
* **依賴 API 模組**: `@frontend/api.js` (已提供 `fetchMoods` 和 `fetchHabitLogs` 函式)。
# 關鍵架構決策 (Key Architectural Decisions)
1. **單一圖表實例 (Single Chart Instance)**: 為避免重複渲染導致的效能問題,我們必須在全域範圍內維護一個**唯一的圖表實例變數** (例如 `let insightChartInstance = null;`)。渲染函式在首次執行時建立圖表,後續僅更新其數據 (`chart.update()`),而非銷毀重建。
2. **設計系統同步 (Theme Synchronization)**: 圖表的所有顏色和字體,都**必須**從 CSS 變數中動態讀取,以確保視覺風格與 Style Guide 永遠保持一致。
-----
## 產出格式與要求 (Your Task & Output Requirements)
**請直接修改 `@frontend/script.js`,追加新的程式碼,並對現有邏輯進行整合。**
### 1\. **升級狀態中心 (`state`)**
* 在全域 `state` 物件中,新增用於儲存圖表相關數據的屬性:
```javascript
const state = {
// ... existing state
moods: [],
habitLogs: [],
// We don't store the processed chart data in the state,
// as it's derived data.
};
```
### 2\. **數據處理邏輯**
* **整合 `loadInitialData`**:
* 在 `loadInitialData` 函式中,使用 `Promise.all` **同時**獲取 `habits`, `moods`, `habitLogs` 的數據。
* 成功獲取後,將**原始數據**存入 `state` 中:`setState({ habits, moods, habitLogs, isLoading: false })`。
* **建立 `processChartData` 輔助函式**:
* 建立一個**純函式 (Pure Function)** `processChartData(moods, habitLogs)`。
* 其唯一職責是接收原始數據陣列,並**嚴格按照**規格書中 `data` Prop 的定義,回傳處理成圖表所需的格式:`[{ date, moodRating, completedHabits: [...] }, ...]`。
### 3\. **圖表渲染函式 (`renderInsightChart`)**
* 在檔案頂部,宣告 `let insightChartInstance = null;`。
* 建立 `renderInsightChart(chartData)` 函式,其邏輯如下:
1. **獲取畫布**: 取得 `<canvas id="insightChart">` 元素。
2. **處理邊界情況**: 嚴格遵循規格書,檢查傳入的 `chartData` 長度。如果數據不足,需**銷毀**現有圖表實例 (`insightChartInstance?.destroy()`),並在容器中顯示提示訊息,然後提前返回。
3. **更新或建立**:
* 如果 `insightChartInstance` **已存在**,則只更新其數據 (`insightChartInstance.data = ...`) 和選項,然後呼叫 `insightChartInstance.update()`。
* 如果 `insightChartInstance` **不存在**,則使用 `new Chart(...)` 建立一個新的圖表實例,並將其賦值給 `insightChartInstance`。
4. **Chart.js Config 設定**:
* **嚴格遵循**規格書中「核心功能」與「互動行為」的所有要求來設定 `config` 物件(混合圖表類型、座標軸、Tooltip 回呼等)。
* **顏色與字體**: 所有的顏色(線條、背景、標記點)和字體設定,都必須透過輔助函式從 CSS 變數動態獲取,**禁止硬編碼**。
### 4\. **整合主渲染流程 (`render`)**
* 修改主 `render` 函式:
* 在 `render` 函式的邏輯中,先從 `state` 讀取原始數據:`const { moods, habitLogs } = state;`。
* 呼叫 `const processedData = processChartData(moods, habitLogs);` 來得到處理後的數據。
* 最後呼叫 `renderInsightChart(processedData);`,將渲染圖表的任務交給專門的函式。
### 5\. **(可選) 建立 CSS 變數讀取輔助函式**
* 建議在檔案中加入一個小巧的輔助函式,用於在 JavaScript 中讀取 `:root` 中的 CSS 變數值。
```javascript
const getCssVariable = (varName) => getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
```
是時候驗收了!再次確保所有伺服器都在運行,然後刷新你的瀏覽器。
這一次,在我們的習慣列表上方,你會看到一幅美麗的畫卷:
一條藍色的線條,優雅地描繪出你過去一段時間的心情起伏。而在某些日期上,點綴著珊瑚色的圓點,標示著你完成習慣的「高光時刻」。把滑鼠移上去,一個詳細的 Tooltip 會告訴你那天的所有故事。
我們成功了! 我們將冰冷的數據,轉化為了富有情感的、能啟發洞察的視覺化故事。這正是我們專案的核心價值所在!
feat(frontend): implement insight chart based on spec
再次恭喜!今天,我們的 App 真正地從一個「好用的工具」,進化成了一個**「有價值的夥伴」**。它不再只是一個紀錄器,它現在是一個能夠幫助使用者反思、發現自我的數據分析師。
我們也再次證明了「文件驅動開發」的巨大威力。正因為有了昨天那份滴水不漏的規格書,我們今天才能如此從容、精準地 Vibe Coding 出如此複雜的功能。
我們的 MVP 核心功能已全部完成。但還有最後一道、也是最重要的一道門沒有建立。明天,我們將再次回歸「文件驅動」,為我們的專案設計並實現專業、安全的使用者認證流程!